package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.AdChannelService;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.constants.message.ArticleForEsConstants;
import com.heima.common.exception.CustomException;
import com.heima.feigns.article.ArticleFeign;
import com.heima.feigns.wemedia.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;


@Service
@Slf4j
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {
    @Autowired
    WemediaFeign wemediaFeign;
    @Autowired
    GreenTextScan greeTextScan;
    @Autowired
    GreenImageScan greenImageScan;

    @Value("${file.oss.web-site}")
    private String webSite;

    @GlobalTransactional
    @Transactional
    @Override
    public void autoScanByMediaNewsId(Integer wmNewsId) {
        //检查参数
        if (wmNewsId == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据id查询新闻
        WmNews news = wemediaFeign.findById(wmNewsId);
        if (news == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST, "文章不存在");
        }
        //如果新闻状态为4且发布时间小于当前时间立即发布文章
        if ((news.getStatus().equals(WmNews.Status.ADMIN_SUCCESS.getCode()) && news.getPublishTime().getTime() <= System.currentTimeMillis()))
        //保存数据
        {
            publishArticle(news);
            return;
        }
        //如果新闻状态为/且发布时间小于当前时间立即发布文章
        if ((news.getStatus().equals(WmNews.Status.SUCCESS.getCode()) && news.getPublishTime().getTime() <= System.currentTimeMillis())) {
            //保存数据
            publishArticle(news);
            return;
        }
        //如果文章状态是则开始审核
        if (news.getStatus().equals(WmNews.Status.SUBMIT.getCode())) {
            //获取文章内容和图片map数据
            Map<String, Object> contentAndImagesResult = handleTextAndImages(news);
            //自管理敏感词审核
            boolean isSensitiveScan = handleSensitive((String) contentAndImagesResult.get("content"), news);
            if (!isSensitiveScan) return;
            //阿里云文本审核
            boolean isTextScan = handleTextScan((String) contentAndImagesResult.get("content"), news);
            if (!isTextScan) return;
            //阿里云图片审核
            boolean isImageScan = handleImagesScan((List) contentAndImagesResult.get("images"), news);
            if (!isImageScan) return;
            //如果发布时间大于当前时间则修改news 文章状态=8
            if (news.getPublishTime().getTime()>System.currentTimeMillis()){
                updateWmNews(news,WmNews.Status.SUCCESS.getCode(),"文章审核通过，待发布");
                return;
            }
            //审核通过，保存文章相关信息（三张表）， 修改文章的状态=9 已发布
            publishArticle(news);
        }
    }

    private boolean handleImagesScan(List<String> images, WmNews news) {
        // 无图则无需审核
        if (images == null || images.size() == 0) {
            return true;
        }
        boolean flag = true;
        try {
            images = images
                    .stream()
                    .distinct()
                    .collect(Collectors.toList());
            Map map = greenImageScan.imageUrlScan(images);
            //审核不通过
            if (map.get("suggestion").equals("block")) {
                updateWmNews(news, (short) 2, "文章图片有违规");
                flag = false;
            }
            //人工审核
            if (map.get("suggestion").equals("review")) {
                updateWmNews(news, (short) 3, "文章图片有不确定元素");
                flag = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            updateWmNews(news, (short) 3, "阿里云审核失败，转入人工审核");
            flag = false;
        }
        return flag;
    }

    private boolean handleTextScan(String content, WmNews news) {
        boolean flag = true;
        try {
            Map map = greeTextScan.greenTextScan(content);
            //审核不通过
            if (map.get("suggestion").equals("block")) {
                flag = false;
                updateWmNews(news, (short) 2, "文本中内容有敏感词汇");
            }
            //需要人工审核
            if (map.get("suggestion").equals("review")) {
                flag = false;
                updateWmNews(news, (short) 3, "文本中内容需要人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("文章阿里云内容审核失败，转入人工审核, e：{}", e);
            flag = false;
            updateWmNews(news, (short) 3, "文章阿里云内容审核失败,转入需要人工审核");
        }
        return flag;
    }

    @Autowired
    AdSensitiveMapper adSensitiveMapper;

    private boolean handleSensitive(String content, WmNews news) {
        boolean flag = true;
        //查找敏感词
        List<String> allSensitive = adSensitiveMapper.findAllSensitive();
        // 初始化 DFA搜索
        SensitiveWordUtil.initMap(allSensitive);
        // 匹配敏感词
        Map<String, Integer> mapReq = SensitiveWordUtil.matchWords(content);
        //返回集合不为空则包含敏感词
        if (mapReq != null && !mapReq.isEmpty()) {
            flag = false;
            //更新文章状态为2审核未通过
            updateWmNews(news, (short) 2, "文章中包含了敏感词:" + mapReq);
        }
        return flag;
    }

    private void updateWmNews(WmNews news, short status, String reason) {
        //设置文章审核状态和未通过原因
        news.setStatus(status);
        news.setReason(reason);
        //根据feign接口调用方法更新文章状态
        ResponseResult responseResult = wemediaFeign.updateWmNews(news);
        //如果返回结果不为0则更新失败。抛出异常
        if (responseResult.getCode() != 0) {
            throw new CustomException(AppHttpCodeEnum.SERVER_ERROR, responseResult.getErrorMessage());
        }
    }

    private Map<String, Object> handleTextAndImages(WmNews news) {
        //获取新闻内容
        String content = news.getContent();
        //判断是否为空
        if (StringUtils.isBlank(content)) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST, "文章为空");
        }
        //将新闻内容转换为list<map>集合
        List<Map> contentList = JSON.parseArray(content, Map.class);
        String contents = contentList.stream()
                .filter(x -> x.get("type").equals("text"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.joining("_hmtt_"));
        //文章标题参与审核
        contents = news.getTitle() + "_hmtt_" + contents;
        //处理内容图片
        List<String> images = contentList.stream()
                .filter(x -> x.get("type").equals("image"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.toList());
        //处理封面前缀
        String imageCover = news.getImages();
        if (StringUtils.isNotBlank(imageCover)) {
            //添加封面到内容图片列表参见审核
            images.addAll(Stream.of(imageCover.split(","))
                    .map(x -> webSite + x)
                    .collect(Collectors.toList()));
        }
        //封装数据
        HashMap<String, Object> map = new HashMap<>();
        map.put("content", contents);
        map.put("image", images);
        return map;
    }
   @Autowired
    KafkaTemplate kafkaTemplate;
    /**
     * 保存APP端文章相关数据
     *
     * @param news
     */
    private void publishArticle(WmNews news) {
        //保存app相关文章
        ResponseResult responseResult = saveArticle(news);
        if(!responseResult.getCode().equals(0)){
            throw new CustomException(AppHttpCodeEnum.FILE_UPLOAD_ERROR,"文章审核保存app文章失败");
        }
        Object data = responseResult.getData();
        news.setArticleId((Long)data);
        updateWmNews(news,(short)9,"审核通过");
        //创建索引（为后续app端的搜索功能做数据准备）
        // ==============新加代码==============================================
        Map map = new HashMap();
        map.put("articleId",news.getArticleId());
        kafkaTemplate.send(ArticleForEsConstants.ARTICLE_ELASTICSEARCH_ADD,JSON.toJSONString(map));
    }
     @Autowired
    AdChannelMapper adChannelMapper;

    @Autowired
    ArticleFeign articleFeign;
    private ResponseResult saveArticle(WmNews news) {
        //封装数据 dto
        ArticleDto articleDto = new ArticleDto();
        articleDto.setId(null);
        if (news.getArticleId()!=null) {
            articleDto.setId(news.getArticleId() );
        }
        BeanUtils.copyProperties(news,articleDto);
        articleDto.setLayout(news.getType());
        // 布局
        articleDto.setFlag((byte) 0);

        //2 设置频道
        if (news.getChannelId() != null) {
            articleDto.setChannelId(news.getChannelId());
            AdChannel channel = adChannelMapper.selectById(news.getChannelId());
            if (channel != null) {
                articleDto.setChannelName(channel.getName());
            }
        }
        //设置作者信息
        // 查wm_user 状态
        WmUser wmUser = wemediaFeign.findWmUserById(news.getUserId());
        if (wmUser == null || wmUser.getStatus().intValue() != 9) { // 非法用户
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST,"非法用户");
        }
        if (StringUtils.isNotBlank(wmUser.getName())) {
            // 自媒体名称不能修改
            articleDto.setAuthorName(wmUser.getName());
            // 作者id 尽量减少远程调用
        }
        //文章内容
        articleDto.setContent(news.getContent());

        // 发起远程调用 保存 三张表数据, 返回值必须携带文章id
        return articleFeign.saveArticle(articleDto);
    }
}
